Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of the canopy model #288

Merged
merged 27 commits into from
Sep 25, 2024

Conversation

davidorme
Copy link
Collaborator

@davidorme davidorme commented Sep 18, 2024

Description

[Updated to move from WIP to ready to merge].

This PR is to review, adapt and merge in @AmyOctoCat's code on the canopy object from #231.

The main areas of change from that PR are:

  • The t_model_functions and canopy_functions modules have now settled down to which functions belong in which
    module.
  • Thecanopy_functions module has now been extended to include the canopy vertical structure functions from WIP - 230 create a draft canopy class #231, including the relative canopy radius, stem crown area and stem leaf area at given heights, along with a solver function to find the height at which a canopy layer closes. This includes:
    • Rethinking the workflow for functions to avoid repetitive calculation.
    • Removing Community object as an argument within the canopy_functions functions and replacing it with explicit arguments for the community properties for each function. This makes the core functions more flexible.
    • Adding a bunch of validation for input shapes of canopy function arguments, but making it optional for a speed-up within solvers and classes where the shapes can be assumed correct.
  • The Canopy object has been reworked to use this new functionality to get to the same end point as in WIP - 230 create a draft canopy class #231.
  • I've also added unit tests for the canopy functions and a really simple test of the Canopy object.

In addition, from the earlier WIP version of the PR, this code:

  • is updated to drop use of pandas data structure in favour of simple use of numpy arrays throughout (see Replace use of pandas in pyrealm.demography #292).
  • updates the t_model_functions to include validation of the input argument shapes and then builds out a deeper unit test suite to a range of input combinations using predictions from the original R implementation.

Things to do later:

  • Update the docstrings with better docs on the equations and then update the canopy.md document to use this code.
  • More functionality needed in the Canopy object to use it to generate absorbed radiation per stem per layer and hence generate productivity estimates.

Fixes #286 (issue)

Type of change

  • New feature (non-breaking change which adds functionality)
  • Optimization (back-end change that speeds up the code)
  • Bug fix (non-breaking change which fixes an issue)

Key checklist

  • Make sure you've run the pre-commit checks: $ pre-commit run -a
  • All tests pass: $ poetry run pytest

Further checks

  • Code is commented, particularly in hard-to-understand areas
  • Tests added that prove fix is effective or that feature works

@davidorme davidorme linked an issue Sep 18, 2024 that may be closed by this pull request
@codecov-commenter
Copy link

codecov-commenter commented Sep 19, 2024

Codecov Report

Attention: Patch coverage is 99.33333% with 1 line in your changes missing coverage. Please review.

Project coverage is 95.54%. Comparing base (1f315ba) to head (c2814e3).
Report is 97 commits behind head on develop.

Files with missing lines Patch % Lines
pyrealm/demography/canopy.py 97.87% 1 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff             @@
##           develop     #288      +/-   ##
===========================================
+ Coverage    95.29%   95.54%   +0.25%     
===========================================
  Files           28       34       +6     
  Lines         1720     2243     +523     
===========================================
+ Hits          1639     2143     +504     
- Misses          81      100      +19     
Flag Coverage Δ
95.54% <99.33%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

pyrealm/demography/canopy.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
tests/unit/demography/test_t_model_functions.py Outdated Show resolved Hide resolved
omarjamil
omarjamil previously approved these changes Sep 20, 2024
Copy link
Collaborator

@omarjamil omarjamil left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, this is a well-structured and thoroughly documented piece of scientific code. The use of numpy, type hinting, and input validation contributes to its robustness. My suggestions are for further improvement of the code, but not critical.

pyrealm/demography/canopy.py Show resolved Hide resolved
pyrealm/demography/canopy.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
raise ValueError("Invalid shape for the z value.")


def calculate_relative_canopy_radius_at_z(
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the inputs array can be reshaped to be broadcastable, then using numpy functions instead of python built-ins e.g. np.power instead of **can help with vectorization and improve performance.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I need to think about (and document) what shapes are sensible here. I believe that M**n is faster if n is a scalar but np.power(M, n) is faster when n is an array? Could get either in using this function.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think np.power will be faster if you are applying the operation to an array even if the exponent is a scaler. And you can further performance gains if you can apply np.vectorize to functions. Though I feel like I need to back up this with some testing!

@omarjamil
Copy link
Collaborator

I should add that I am happy to defer to James and Marion in terms of what they consider to important changes to make as they have better code and project knowledge than me.

@davidorme davidorme marked this pull request as ready for review September 23, 2024 15:03
Copy link
Collaborator

@j-emberton j-emberton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't had a in depth look at the tests yet, but generally this looks OK.
It'd be good to get some thoughts on the potential type inconsistencies for m,n and q_m in canopy_functions.py.
I would prefer to see canopy.py refactored to move the evaluations out of the constructor.

pyrealm/demography/canopy.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Outdated Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
pyrealm/demography/canopy_functions.py Show resolved Hide resolved
@davidorme davidorme dismissed omarjamil’s stale review September 24, 2024 20:48

Approving review of early WIP version - needs approval of current proposed final version

@davidorme
Copy link
Collaborator Author

@j-emberton The calculate_canopy_q_m and calculate_canopy_z_max_proportion should definitely return float | NDArray but for the other functions, isn't the typing simply saying that this function requires an array of values for q_m, m, n and z_max_proportion. It doesn't matter what type the original function generates as long as any intermediate code packs up values into arrays for use here.

I guess the danger is that users might (not unreasonably) stick the float outputs of those two functions straight into the other functions, but that is intentionally an error - I don't want these functions to support float inputs.

@j-emberton
Copy link
Collaborator

@j-emberton The calculate_canopy_q_m and calculate_canopy_z_max_proportion should definitely return float | NDArray but for the other functions, isn't the typing simply saying that this function requires an array of values for q_m, m, n and z_max_proportion. It doesn't matter what type the original function generates as long as any intermediate code packs up values into arrays for use here.

I guess the danger is that users might (not unreasonably) stick the float outputs of those two functions straight into the other functions, but that is intentionally an error - I don't want these functions to support float inputs.

Yeah, I see. I think I was being a bit overzealous here, and got into a mindset where those type inconsistencies in calculate_canopy_q_m would be able to propagate into the other functions. But I see that's not the case.

@davidorme
Copy link
Collaborator Author

@j-emberton I think with that update to the Canopy.__init__ and the improved validation, this is now in good shape. Could you approve? Unless, of course, you don't 😥 ...

@j-emberton
Copy link
Collaborator

@j-emberton I think with that update to the Canopy.__init__ and the improved validation, this is now in good shape. Could you approve? Unless, of course, you don't 😥 ...

👼 🤔 😈

will go ahead and approve

@j-emberton j-emberton self-requested a review September 25, 2024 13:39
Copy link
Collaborator

@j-emberton j-emberton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes

@davidorme davidorme merged commit 2e98cb6 into develop Sep 25, 2024
12 checks passed
@davidorme davidorme deleted the 286-implementation-of-the-canopy-model branch September 25, 2024 13:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

Implementation of the Canopy model
5 participants